package com.fxd.util;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fxd.model.Fruit;

import java.util.HashMap;
import java.util.Map;

/**
 * 封装jackson
 * 映射器实例是完全线程安全的，前提是实例的所有配置都发生在任何读取或写入调用之前。
 * 如果在第一次使用后修改了映射器的配置，则更改可能会或可能不会生效，并且配置调用本身可能会失败。
 * 如果您需要使用不同的配置，您有两种主要可能性：
 * 1，ObjectReader为阅读、ObjectWriter写作而构建和使用。这两种类型都是完全不可变的，
 * 您可以使用工厂方法ObjectMapper或读取器/写入器本身自由地创建具有不同配置的新实例。
 * new ObjectReaders and ObjectWriters是一个非常轻量级的操作，因此通常可以根
 * 据需要在每次调用的基础上创建它们，以配置诸如 JSON 的可选缩进之类的东西。
 * 2，如果特定类型的可配置性无法通过new ObjectReaders and ObjectWriters获得，您可能需要使用多
 * 个ObjectMapper来代替（例如：您不能即时更改混合注释；或者，一组自定义（反）序列化器）。
 * 为了帮助这种用法，您可能需要使用copy()创建具有特定配置的映射器克隆的方法，并允许在
 * 复制实例被使用之前对其进行配置。请注意，copy()操作与构建新实例一样昂贵ObjectMapper：
 * 如果可能，如果您打算将映射器用于多个操作，您仍然应该合并和重用它们。
 * 来源：https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/ObjectMapper.html
 */
public class JacksonUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();  //饿汉模式

    /**
     * 默认配置
     * 序列化  object->T
     * 反序列化  T->object
     */
    static {
        //序列化时，对象为空，不抛出异常
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //反序列化时，属性比对象的属性多，不抛出异常
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    private JacksonUtil() {
    }

    public static <K, V, T> T map2Object(Map<K, V> fromMap, Class<T> toObject) {
        return objectMapper.convertValue(fromMap, toObject);
    }

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("name", "apple");
        map.put("price", "6");
        map.put(".class", "f");
        Fruit fruit = map2Object(map, Fruit.class);
        System.out.println(fruit);
    }

}
